import socket
import struct
import time
from threading import Thread
from ipaddress import ip_address

# 组播IP范围
MULTICAST_START = ip_address("224.0.0.0")
MULTICAST_END = ip_address("239.255.255.255")

# 响应设备集合
responding_devices = set()


def send_probes():
    """发送组播探测包"""
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)

    current_ip = MULTICAST_START
    while current_ip <= MULTICAST_END:
        multicast_group = str(current_ip)
        port = MULTICAST_PORT  # 使用任意端口

        try:
            # 发送简单的探测消息
            message = b"PROBE"
            sock.sendto(message, (multicast_group, port))
            print(f"Sent probe to {multicast_group}")

            # 小延迟避免洪水攻击
            time.sleep(0.01)

        except Exception as e:
            print(f"Error sending to {multicast_group}: {e}")

        current_ip += 1


RECV_PORT = 10134  # 设备发送多播响应的端口
MULTICAST_PORT = 10131  # 用于发送多播查询的端口

def listen_responses():
    """监听响应"""
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind(('0.0.0.0', RECV_PORT))  # 绑定到发送探测的同一端口

    while True:
        try:
            data, addr = sock.recvfrom(1024)
            if data and addr[0] not in responding_devices:
                responding_devices.add(addr[0])
                print(f"\n[+] Device responded: {addr[0]}")
                print(f"    Response data: {data.decode('utf-8', errors='ignore')}\n")

        except KeyboardInterrupt:
            break
        except Exception as e:
            print(f"Error receiving: {e}")


def main():
    print("Starting multicast scanner...")
    print(f"Scanning range: {MULTICAST_START} to {MULTICAST_END}")

    # 启动监听线程
    listener = Thread(target=listen_responses)
    listener.daemon = True
    listener.start()

    # 发送探测
    send_probes()

    # 等待所有探测发送完成
    print("\nFinished sending all probes. Waiting for responses...")

    # 等待一段时间让所有响应到达
    time.sleep(10)

    # 打印汇总
    print("\nScan complete. Responding devices:")
    for device in sorted(responding_devices):
        print(f" - {device}")


if __name__ == "__main__":
    main()